package online.foxnull2.foxmall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import online.foxnull2.common.constant.ProductConstant;
import online.foxnull2.common.to.SkuFullReductionTo;
import online.foxnull2.common.to.SkuLadderTo;
import online.foxnull2.common.to.SkuMemberPriceTo;
import online.foxnull2.common.to.SpuBoundsTo;
import online.foxnull2.common.to.es.SkuEsModel;
import online.foxnull2.common.utils.R;
import online.foxnull2.foxmall.product.entity.*;
import online.foxnull2.foxmall.product.feign.CouponFeignService;
import online.foxnull2.foxmall.product.feign.SearchFeignService;
import online.foxnull2.foxmall.product.feign.WareFeignService;
import online.foxnull2.foxmall.product.mapper.SpuInfoMapper;
import online.foxnull2.foxmall.product.service.*;
import online.foxnull2.foxmall.product.utils.PageUtils;
import online.foxnull2.foxmall.product.utils.Query;
import online.foxnull2.foxmall.product.vo.spu.*;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoMapper, SpuInfoEntity> implements SpuInfoService {

    private final SpuInfoDescService spuInfoDescService;
    private final SpuImagesService spuImagesService;
    private final AttrService attrService;
    private final ProductAttrValueService productAttrValueService;
    private final SkuInfoService skuInfoService;
    private final SkuImagesService skuImagesService;
    private final SkuSaleAttrValueService skuSaleAttrValueService;
    private final CouponFeignService couponFeignService;
    private final BrandService brandService;
    private final CategoryService categoryService;
    private final WareFeignService wareFeignService;
    private final SearchFeignService searchFeignService;

    @Autowired
    public SpuInfoServiceImpl(SpuInfoDescService spuInfoDescService,
                              SpuImagesService spuImagesService,
                              AttrService attrService,
                              ProductAttrValueService productAttrValueService,
                              SkuInfoService skuInfoService,
                              SkuImagesService skuImagesService,
                              SkuSaleAttrValueService skuSaleAttrValueService,
                              CouponFeignService couponFeignService,
                              BrandService brandService,
                              CategoryService categoryService,
                              WareFeignService wareFeignService,
                              SearchFeignService searchFeignService) {
        this.spuInfoDescService = spuInfoDescService;
        this.spuImagesService = spuImagesService;
        this.attrService = attrService;
        this.productAttrValueService = productAttrValueService;
        this.skuInfoService = skuInfoService;
        this.skuImagesService = skuImagesService;
        this.skuSaleAttrValueService = skuSaleAttrValueService;
        this.couponFeignService = couponFeignService;
        this.brandService = brandService;
        this.categoryService = categoryService;
        this.wareFeignService = wareFeignService;
        this.searchFeignService = searchFeignService;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> queryWrapper = new QueryWrapper<>();
        Object key = params.get("key");
        if (!ObjectUtils.isEmpty(key)) {
            queryWrapper.and(wrapper -> wrapper.eq("id", key).or().like("spu_name", key));
        }
        Object catelogId = params.get("catelogId");
        if (!ObjectUtils.isEmpty(catelogId)) {
            queryWrapper.eq("catalog_id", catelogId);
        }
        Object brandId = params.get("brandId");
        if (!ObjectUtils.isEmpty(brandId)) {
            queryWrapper.eq("brand_id", brandId);
        }
        Object status = params.get("status");
        if (!ObjectUtils.isEmpty(status)) {
            queryWrapper.eq("publish_status", status);
        }

        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void saveCascade(SpuVo spuVo) {
        //spu info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        spuInfoEntity
                .setSpuName(spuVo.getSpuName())
                .setSpuDescription(spuVo.getSpuDescription())
                .setCatalogId(spuVo.getCatalogId())
                .setBrandId(spuVo.getBrandId())
                .setWeight(spuVo.getWeight())
                .setPublishStatus(spuVo.getPublishStatus())
                .setCreateTime(new Date())
                .setUpdateTime(new Date());
        this.save(spuInfoEntity);
        Long spuInfoEntityId = spuInfoEntity.getId();
        //spu info desc
        List<String> decript = spuVo.getDecript();
        if (!ObjectUtils.isEmpty(decript)) {
            SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
            spuInfoDescEntity
                    .setSpuId(spuInfoEntityId)
                    .setDecript(String.join(",", decript));
            spuInfoDescService.save(spuInfoDescEntity);
        }
        //spu info images
        List<String> images = spuVo.getImages();
        if (!ObjectUtils.isEmpty(images)) {
            List<SpuImagesEntity> spuImagesEntityList = images.stream().map(image -> {
                SpuImagesEntity spuImagesEntity = new SpuImagesEntity();
                spuImagesEntity
                        .setSpuId(spuInfoEntityId)
                        .setImgUrl(image);
                return spuImagesEntity;
            }).collect(Collectors.toList());
            spuImagesService.saveBatch(spuImagesEntityList);
        }
        //product attr value
        List<BaseAttrs> baseAttrsList = spuVo.getBaseAttrs();
        if (!ObjectUtils.isEmpty(baseAttrsList)) {
            List<ProductAttrValueEntity> productAttrValueEntityList = baseAttrsList.stream().map(baseAttrs -> {
                        ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
                        AttrEntity attrEntity = attrService.getById(baseAttrs.getAttrId());
                        if (!ObjectUtils.isEmpty(attrEntity)) {
                            productAttrValueEntity
                                    .setSpuId(spuInfoEntityId)
                                    .setAttrId(baseAttrs.getAttrId())
                                    .setAttrName(attrEntity.getAttrName())
                                    .setAttrValue(baseAttrs.getAttrValues())
                                    .setQuickShow(baseAttrs.getShowDesc());
                        }
                        return productAttrValueEntity;
                    }).filter(productAttrValueEntity -> !ObjectUtils.isEmpty(productAttrValueEntity.getAttrId()))
                    .collect(Collectors.toList());
            if (!ObjectUtils.isEmpty(productAttrValueEntityList)) {
                productAttrValueService.saveBatch(productAttrValueEntityList);
            }
        }
        //foxmall_sms -> spu bounds
        Bounds bounds = spuVo.getBounds();
        SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
        spuBoundsTo
                .setSpuId(spuInfoEntityId)
                .setGrowBounds(bounds.getGrowBounds())
                .setBuyBounds(bounds.getBuyBounds());
        couponFeignService.saveSpuBounds(spuBoundsTo);
        //sku info
        List<Skus> skus = spuVo.getSkus();
        if (!ObjectUtils.isEmpty(skus)) {
            skus.forEach(sku -> {
                String defaultImg = "";
                for (Images image : sku.getImages()) {
                    if (1 == image.getDefaultImg()) {
                        defaultImg = image.getImgUrl();
                    }
                }
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                skuInfoEntity
                        .setSpuId(spuInfoEntityId)
                        .setSkuName(sku.getSkuName())
                        .setSkuDesc("")
                        .setCatalogId(spuInfoEntity.getCatalogId())
                        .setBrandId(spuInfoEntity.getBrandId())
                        .setSkuDefaultImg(defaultImg)
                        .setSkuTitle(sku.getSkuTitle())
                        .setSkuSubtitle(sku.getSkuSubtitle())
                        .setPrice(sku.getPrice())
                        .setSaleCount(0L);
                skuInfoService.save(skuInfoEntity);
                Long skuId = skuInfoEntity.getSkuId();
                //sku images
                List<Images> skuImagesList = sku.getImages();
                if (!ObjectUtils.isEmpty(skuImagesList)) {
                    List<SkuImagesEntity> skuImagesEntityList = skuImagesList.stream().map(skuimages -> {
                                SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                                skuImagesEntity
                                        .setSkuId(skuId)
                                        .setImgUrl(skuimages.getImgUrl())
                                        .setDefaultImg(skuimages.getDefaultImg());
                                return skuImagesEntity;
                            }).filter(skuImagesEntity -> !ObjectUtils.isEmpty(skuImagesEntity.getImgUrl()))
                            .collect(Collectors.toList());
                    if (!ObjectUtils.isEmpty(skuImagesEntityList)) {
                        skuImagesService.saveBatch(skuImagesEntityList);
                    }
                }
                //sku sale attr value
                List<Attr> attrList = sku.getAttr();
                if (!ObjectUtils.isEmpty(attrList)) {
                    List<SkuSaleAttrValueEntity> skuSaleAttrValueEntityList = attrList.stream().map(attr -> {
                        SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                        skuSaleAttrValueEntity
                                .setSkuId(skuId)
                                .setAttrId(attr.getAttrId())
                                .setAttrName(attr.getAttrName())
                                .setAttrValue(attr.getAttrValue());
                        return skuSaleAttrValueEntity;
                    }).collect(Collectors.toList());
                    skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntityList);
                }
                //foxmall_sms -> sku ladder
                if (0 < sku.getFullCount()) {
                    SkuLadderTo skuLadderTo = new SkuLadderTo();
                    skuLadderTo
                            .setSkuId(skuId)
                            .setFullCount(sku.getFullCount())
                            .setDiscount(sku.getDiscount())
                            .setPrice(sku.getPrice())
                            .setAddOther(sku.getCountStatus());
                    couponFeignService.saveSkuLadder(skuLadderTo);
                }
                //foxmall_sms -> full reduction
                if (sku.getFullPrice().compareTo(new BigDecimal("0")) > 0) {
                    SkuFullReductionTo skuFullReductionTo = new SkuFullReductionTo();
                    skuFullReductionTo
                            .setSkuId(skuId)
                            .setFullPrice(sku.getFullPrice())
                            .setReducePrice(sku.getReducePrice())
                            .setAddOther(sku.getPriceStatus());
                    couponFeignService.saveSkuFullReductin(skuFullReductionTo);
                }

                //foxmall_sms -> member price
                List<MemberPrice> memberPrices = sku.getMemberPrice();
                if (!ObjectUtils.isEmpty(memberPrices)) {
                    List<SkuMemberPriceTo> skuMemberPriceToList = memberPrices.stream().map(memberPrice -> {
                                SkuMemberPriceTo skuMemberPriceTo = new SkuMemberPriceTo();
                                skuMemberPriceTo
                                        .setSkuId(skuId)
                                        .setMemberLevelId(memberPrice.getId())
                                        .setMemberLevelName(memberPrice.getName())
                                        .setMemberPrice(memberPrice.getPrice());
                                return skuMemberPriceTo;
                            }).filter(skuMemberPriceTo -> 0 < skuMemberPriceTo.getMemberPrice().compareTo(new BigDecimal("0")))
                            .collect(Collectors.toList());
                    if (!ObjectUtils.isEmpty(skuMemberPriceToList)) {
                        couponFeignService.saveSkuMemberPrices(skuMemberPriceToList);
                    }
                }

            });
        }
    }

    @Override
    public void spuUp(Long spuId) {
        List<SkuInfoEntity> skuInfoEntityList = skuInfoService.list(new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId));

        List<ProductAttrValueEntity> productAttrValueEntityList = productAttrValueService.baseListforspuBySpuId(spuId);
        List<Long> attrIdList = productAttrValueEntityList.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());

        List<AttrEntity> attrEntityList = attrService.list(new QueryWrapper<AttrEntity>()
                .in("attr_id", attrIdList).eq("search_type", 1)
                .select("attr_id"));
        Set<Long> attrIdSet = attrEntityList.stream().map(AttrEntity::getAttrId).collect(Collectors.toSet());
        List<SkuEsModel.Attr> attrs = productAttrValueEntityList.stream()
                .filter(productAttrValueEntity -> attrIdSet.contains(productAttrValueEntity.getAttrId()))
                .map(productAttrValueEntity -> {
                    SkuEsModel.Attr attr = new SkuEsModel.Attr();
                    attr.setAttrId(productAttrValueEntity.getAttrId())
                            .setAttrName(productAttrValueEntity.getAttrName())
                            .setAttrValue(productAttrValueEntity.getAttrValue());
                    return attr;
                }).collect(Collectors.toList());
        Set<Long> skuIdSet = null;
        try {
            skuIdSet = wareFeignService.getSkuHasStock(attrIdList);
        } catch (Exception e) {
            log.error("wareFeignService.getSkuHasStock(attrIdList) error {}", e.getMessage());
        }

        Set<Long> finalSkuIdSet = skuIdSet;
        List<SkuEsModel> skuEsModelList = skuInfoEntityList.stream().map(skuInfoEntity -> {
            SkuEsModel skuEsModel = new SkuEsModel();
            skuEsModel.setSkuId(skuInfoEntity.getSkuId())
                    .setSpuId(spuId)
                    .setSkuTitle(skuInfoEntity.getSkuTitle())
                    .setSkuPrice(skuInfoEntity.getPrice())
                    .setSkuImg(skuInfoEntity.getSkuDefaultImg())
                    .setSaleCount(skuInfoEntity.getSaleCount())
                    .setBrandId(skuInfoEntity.getBrandId())
                    .setCatalogId(skuInfoEntity.getCatalogId());
            BrandEntity brandEntity = brandService.getById(skuInfoEntity.getBrandId());
            if (ObjectUtils.isNotEmpty(brandEntity)) {
                skuEsModel.setBrandName(brandEntity.getName());
                skuEsModel.setBrandImg(brandEntity.getLogo());
            }
            CategoryEntity categoryEntity = categoryService.getById(skuInfoEntity.getCatalogId());
            if (ObjectUtils.isNotEmpty(categoryEntity)) {
                skuEsModel.setCatalogName(categoryEntity.getName());
            }
            skuEsModel.setAttrs(attrs);
            //TODO
            skuEsModel.setHotScore(0L);

            skuEsModel.setHasStock(ObjectUtils.isEmpty(finalSkuIdSet) || finalSkuIdSet.contains(skuInfoEntity.getSkuId()));
            return skuEsModel;
        }).collect(Collectors.toList());
        R res = searchFeignService.productSave(skuEsModelList);
        if (Objects.equals(res.get("code").toString(), "0")) {
            SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
            spuInfoEntity
                    .setPublishStatus(ProductConstant.PublishStatus.STATUE_UP.getCode())
                    .setUpdateTime(new Date());
            this.update(spuInfoEntity, new UpdateWrapper<SpuInfoEntity>().eq("id", spuId));
        } else {
            //TODO
            log.error("product up hasFailures");
        }
    }

    @Override
    public SpuInfoEntity getSpuInfoBySkuId(Long skuId) {
        SkuInfoEntity skuInfoEntity = skuInfoService.getById(skuId);
        Long spuId = skuInfoEntity.getSpuId();
        SpuInfoEntity spuInfo = baseMapper.selectById(spuId);
        log.debug("getSpuInfoBySkuId -> {}", spuInfo);
        return spuInfo;
    }
}